
var jshared = {
  _socket:null,
  _url:null,
  _cache:null,
  connect:function(url){
    this._url = url;
    this._socket = io.connect(this._url);
    this._cache = {};
  },
  get:function(id, receive){
    var cache = this._cache;
    if(cache[id]){
      receive(cache[id]);
    }else{
      var socket = this._socket;
      socket.emit('jsr.get', id, function(obj){
        obj.setProperty = function(name, value){
          if(obj[name] != value){
            obj[name] = value;
            socket.emit('jsr.change',{
              id:id,
              name:name,
              value:value
            });
          }
        };
        obj.createSetter = function(name){
          obj['set_' + name] = function(value){
            if(obj[name] != value){
              obj[name] = value;
              socket.emit('jsr.change',{
                id:id,
                name:name,
                value:value
              });
            }
          }
        };
        
        obj.createMethod = function(name, handler){
          obj[name] = function(){
            handler.apply(obj, arguments);
            socket.emit('jsr.method',{
              id:id,
              method:name,
              args:Array.prototype.slice.call(arguments)
            });
          }
          obj[name + "_handler"] = handler;
        }
        
        socket.on('jsr.onchange.' + id, function(response){
          var name = response.name;
          var value = response.value;
          obj[name] = value;
          if(obj.changeListener){
            obj.changeListener();
          }
        });
        
        socket.on('jsr.onmethod.' + id, function(response){
          if(response.args){
            obj[response.method + "_handler"].apply(obj, response.args);
          }else{
            obj[response.method + "_handler"]();
          }
        });
        
        receive(obj);
        cache[id] = obj;
      });
    }
  }
};